import { Tabs, Tab } from '@theme';

# Code blocks

Rspress V2 uses [Shiki](https://shiki.style) for syntax highlighting at compile time, which means better runtime performance.

When using code blocks in multiple languages, the corresponding language is automatically detected at compile time, and the runtime bundle size does not increase. For supported programming languages, refer to the [Shiki supported languages list](https://shiki.style/languages).

## Basic usage

You can use the \`\`\` syntax to create code blocks. For example:

````mdx
```js
console.log('Hello World');
```
````

It will be rendered as:

```js
console.log('Hello World');
```

## Code block title

You can use the `title="..."` attribute to add a title to a code block.

````mdx
```jsx title="src/components/HelloCodeBlockTitle.tsx"
const HelloCodeBlockTitle = (props) => {
  return <h1>Hello CodeBlock Title</h1>;
};
```
````

It will be rendered as:

```jsx title="src/components/HelloCodeBlockTitle.tsx"
const HelloCodeBlockTitle = (props) => {
  return <h1>Hello CodeBlock Title</h1>;
};
```

## External file code block

You can use the `file="./path/to/file"` attribute without writing any code block content to reference the text from an external file.

<Tabs>
<Tab label="foo.mdx">

````mdx
```tsx file="./_tsx-component.tsx"

```
````

</Tab>
<Tab label="_tsx-component.tsx">

```tsx file="./_tsx-component.tsx"

```

</Tab>
</Tabs>

It will be rendered as:

```tsx file="./_tsx-component.tsx"

```

:::tip

When using external file code blocks, it's common to use them together with [route conventions](./components.mdx#route-convention). Name files starting with `_`.

:::

## Notation line highlight

You can use [Shiki transformers](#shiki-transformers) with the `transformerNotationHighlight` and `// [!code highlight]` comments to highlight code lines.

<Tabs>
<Tab label="Code">

````mdx
```ts
console.log('Highlighted'); // [\!code highlight]
console.log('Not highlighted');
// [\!code highlight:2]
console.log('Highlighted');
console.log('Highlighted');
```
````

</Tab>
<Tab label="rspress.config.ts">

```ts
import { defineConfig } from '@rspress/core';
import { transformerNotationHighlight } from '@shikijs/transformers';

export default defineConfig({
  markdown: {
    shiki: {
      transformers: [transformerNotationHighlight()],
    },
  },
});
```

</Tab>
</Tabs>

It will be rendered as:

```ts title="highlight.ts"
console.log('Highlighted'); // [!code highlight]
console.log('Not highlighted');
// [!code highlight:2]
console.log('Highlighted');
console.log('Highlighted');
```

:::warning
The backslash (`\`) in `[\!code highlight]` is for escaping in Markdown to show the original syntax. Do not include the backslash when actually using this syntax.
:::

## Meta line highlight

:::warning
When using meta info for line highlighting, be aware that formatting tools may change line numbers. For maintainability, [Notation Line Highlight](#notation-line-highlight) is recommended.
:::

You can use `@rspress/core/shiki-transformers` with `transformerCompatibleMetaHighlight` and meta info comments to highlight code lines.

<Tabs>
<Tab label="Code">

````mdx
```ts {1,3-4}
console.log('Highlighted');
console.log('Not highlighted');
console.log('Highlighted');
console.log('Highlighted');
```
````

</Tab>
<Tab label="rspress.config.ts">

```ts
import { defineConfig } from '@rspress/core';
import { transformerCompatibleMetaHighlight } from '@rspress/core/shiki-transformers';

export default defineConfig({
  markdown: {
    shiki: {
      transformers: [transformerCompatibleMetaHighlight()],
    },
  },
});
```

</Tab>
</Tabs>

It will be rendered as:

```ts {1,3-4}
console.log('Highlighted');
console.log('Not highlighted');
console.log('Highlighted');
console.log('Highlighted');
```

## Show code line numbers

You can show line numbers for individual code blocks using the `lineNumbers` meta attribute:

````mdx
```ts lineNumbers
function hello() {
  console.log('Line numbers enabled for this block');
}
```
````

It will be rendered as:

```ts lineNumbers
function hello() {
  console.log('Line numbers enabled for this block');
}
```

You can also enable line numbers globally by setting the `showLineNumbers` option in the config file:

```ts title="rspress.config.ts"
export default {
  // ...
  markdown: {
    showLineNumbers: true,
  },
};
```

When `showLineNumbers` is enabled globally, all code blocks will show line numbers by default.

## Wrap code

You can enable code wrapping for individual code blocks using the `wrapCode` meta attribute:

````mdx
```ts wrapCode
const longLine =
  'This is a very long line of code that will wrap when the wrapCode meta attribute is present';
```
````

It will be rendered as:

```ts wrapCode
const longLine =
  'This is a very long line of code that will wrap when the wrapCode meta attribute is present';
```

You can also enable code wrapping globally by setting the `defaultWrapCode` option in the config file:

```ts title="rspress.config.ts"
export default {
  // ...
  markdown: {
    defaultWrapCode: true,
  },
};
```

When `defaultWrapCode` is enabled globally, all code blocks will wrap long lines by default.

## Combining meta attributes

You can combine multiple meta attributes together:

````mdx
```ts lineNumbers wrapCode title="example.ts"
const longLine = 'This code block has line numbers, code wrapping, and a title';
```
````

It will be rendered as:

```ts lineNumbers wrapCode title="example.ts"
const longLine = 'This code block has line numbers, code wrapping, and a title';
```

## Diff code block

````mdx
```diff
function test() {
- console.log('deleted');
+ console.log('added');
  console.log('unchanged');
}
```
````

It will be rendered as:

```diff
function test() {
- console.log('deleted');
+ console.log('added');
  console.log('unchanged');
}
```

## Shiki transformers

Rspress V2 uses [Shiki](https://shiki.style) for compile-time code highlighting, providing flexible code block capabilities.

You can add custom [shiki transformers](https://shiki.style/guide/transformers.html) via [`markdown.shiki.transformers`](../../api/config/config-build.mdx#markdownshiki) for richer code block effects.

In addition to the [transformerNotationHighlight](#notation-line-highlight) mentioned above, Rspress defaults to supporting the following transformers from [@shikijs/transformers](https://shiki.style/packages/transformers).

### transformerNotationDiff

<Tabs>
<Tab label="Syntax">

````mdx
```ts
console.log('deleted'); // [\!code --]
console.log('added'); // [\!code ++]
console.log('unchanged');
```
````

</Tab>
<Tab label="rspress.config.ts">

```ts
import { defineConfig } from '@rspress/core';
import { transformerNotationDiff } from '@shikijs/transformers';
export default defineConfig({
  markdown: {
    shiki: {
      transformers: [transformerNotationDiff()],
    },
  },
});
```

</Tab>
</Tabs>

It will be rendered as:

```ts
console.log('deleted'); // [!code --]
console.log('added'); // [!code ++]
console.log('unchanged');
```

### transformerNotationErrorLevel

<Tabs>
<Tab label="Syntax">

````mdx
```ts
console.log('No errors or warnings');
console.error('Error'); // [\!code error]
console.warn('Warning'); // [\!code warning]
```
````

</Tab>
<Tab label="rspress.config.ts">

```ts
import { defineConfig } from '@rspress/core';
import { transformerNotationErrorLevel } from '@shikijs/transformers';
export default defineConfig({
  markdown: {
    shiki: {
      transformers: [transformerNotationErrorLevel()],
    },
  },
});
```

</Tab>
</Tabs>

It will be rendered as:

```ts
console.log('No errors or warnings');
console.error('Error'); // [!code error]
console.warn('Warning'); // [!code warning]
```

### transformerNotationFocus

<Tabs>
<Tab label="Syntax">

````mdx
```ts
console.log('Not focused');
console.log('Focused'); // [\!code focus]
console.log('Not focused');
```
````

</Tab>
<Tab label="rspress.config.ts">

```ts
import { defineConfig } from '@rspress/core';
import { transformerNotationFocus } from '@shikijs/transformers';
export default defineConfig({
  markdown: {
    shiki: {
      transformers: [transformerNotationFocus()],
    },
  },
});
```

</Tab>
</Tabs>

It will be rendered as:

```ts
console.log('Not focused');
console.log('Focused'); // [!code focus]
console.log('Not focused');
```

## Twoslash

> [Twoslash](https://twoslash.netlify.app/guide/) is a markup format for TypeScript code, suitable for creating self-contained code samples and letting the TypeScript compiler automatically supplement type information and hints. It is widely used on the official TypeScript website.

Rspress provides the `@rspress/core/plugin-twoslash` plugin, which enables Twoslash features in Rspress. See [@rspress/plugin-twoslash documentation](../../plugin/official-plugins/twoslash.mdx) for details.

```ts twoslash
// @noErrorValidation
const str: string = 1;
```

## Runtime syntax highlighting

When you need to render code blocks dynamically at runtime, such as in interactive docs or fetching code remotely, Rspress provides the `CodeBlockRuntime` component.

Here is an example:

```mdx title="foo.mdx"
import { CodeBlockRuntime } from '@theme';
import { transformerNotationHighlight } from '@shikijs/transformers';

<CodeBlockRuntime
  lang="ts"
  title="highlight.ts"
  code={`console.log('Highlighted'); // [\!code highlight]
// [\!code highlight:1]
console.log('Highlighted');
console.log('Not highlighted');`}
  shikiOptions={{
    transformers: [transformerNotationHighlight()],
  }}
/>
```

import { CodeBlockRuntime } from '@theme';
import { transformerNotationHighlight } from '@shikijs/transformers';

<CodeBlockRuntime
  lang="ts"
  title="highlight.ts"
  code={`console.log('Highlighted'); // [!code highlight]
// [!code highlight:1]
console.log('Highlighted');
console.log('Not highlighted');`}
  shikiOptions={{
    transformers: [transformerNotationHighlight()],
  }}
/>

:::warning
It is recommended to use `CodeBlockRuntime` only when necessary, as it increases runtime bundle size and cannot benefit from compile-time highlighting performance.
:::
